1 /*
2  * This file is part of gtkD.
3  *
4  * gtkD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 3
7  * of the License, or (at your option) any later version, with
8  * some exceptions, please read the COPYING file.
9  *
10  * gtkD is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with gtkD; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
18  */
19 
20 // generated automatically - do not change
21 // find conversion definition on APILookup.txt
22 // implement new conversion functionalities on the wrap.utils pakage
23 
24 
25 module glib.Spawn;
26 
27 private import core.stdc.stdio;
28 private import core.stdc.string;
29 private import core.thread;
30 private import glib.ErrorG;
31 private import glib.GException;
32 private import glib.Str;
33 private import glib.c.functions;
34 public  import glib.c.types;
35 private import std.string;
36 private import std.traits;
37 
38 
39 /** */
40 public class Spawn
41 {
42 	//we need fdopen.
43 	version(Posix)
44 	{
45 		private import core.sys.posix.stdio;
46 	}
47 	//fdopen for Windows is defined in glib.c.types.
48 
49 	string workingDirectory = ".";
50 	string[] argv;
51 	string[] envp;
52 	GSpawnFlags flags = SpawnFlags.SEARCH_PATH;
53 	GSpawnChildSetupFunc childSetup;
54 	void* userData;
55 	GPid childPid;
56 	FILE* standardInput;
57 	FILE* standardOutput;
58 	FILE* standardError;
59 	GError* error;
60 	int stdIn;
61 	int stdOut;
62 	int stdErr;
63 
64 	// for commandLineSync
65 	int exitStatus;
66 	char* strOutput;
67 	char* strError;
68 
69 	alias bool delegate(Spawn) ChildWatch;
70 	ChildWatch externalWatch;
71 
72 	/**
73 	 * Creates a Spawn for execution.
74 	 */
75 	public this(string program, string[] envp=null)
76 	{
77 		argv ~= program;
78 		this.envp = envp;
79 	}
80 
81 	/**
82 	 * Creates a Spawn for execution.
83 	 */
84 	public this(string[] program, string[] envp=null)
85 	{
86 		argv = program;
87 		this.envp = envp;
88 	}
89 
90 	/**
91 	 * Adds a delegate to be notified on the end of the child process.
92 	 * Params:
93 	 *    	dlg =
94 	 */
95 	public void addChildWatch(ChildWatch dlg)
96 	{
97 		externalWatch = dlg;
98 	}
99 
100 	/**
101 	 * Closes all open streams and child process.
102 	 */
103 	public void close()
104 	{
105 		if (stdIn != 0 )
106 		{
107 			fclose(standardInput);
108 			stdIn = 0;
109 		}
110 		if (stdOut != 0 )
111 		{
112 			fclose(standardOutput);
113 			stdOut = 0;
114 		}
115 		if (stdErr != 0 )
116 		{
117 			fclose(standardError);
118 			stdErr = 0;
119 		}
120 		static if ( isPointer!(GPid) )
121 		{
122 			if ( childPid !is null )
123 			{
124 				closePid(childPid);
125 				childPid = null;
126 			}
127 		}
128 		else
129 		{
130 			if ( childPid != 0 )
131 			{
132 				closePid(childPid);
133 				childPid = 0;
134 			}
135 		}
136 	}
137 
138 	/**
139 	 * Adds a parameter to the execution program
140 	 */
141 	public void addParm(string parm)
142 	{
143 		argv ~= parm;
144 	}
145 
146 	/**
147 	 * Gets the last error message
148 	 */
149 	public string getLastError()
150 	{
151 		if ( error != null )
152 		{
153 			return Str.toString(error.message);
154 		}
155 		return "";
156 	}
157 
158 	/**
159 	 * Executes the prepared process
160 	 */
161 	public int execAsyncWithPipes(
162 		ChildWatch externalWatch = null,
163 		bool delegate(string) readOutput = null,
164 	bool delegate(string) readError = null )
165 	{
166 		int result = g_spawn_async_with_pipes(
167 			Str.toStringz(workingDirectory),
168 			Str.toStringzArray(argv),
169 			Str.toStringzArray(envp),
170 			flags,
171 			childSetup,
172 			userData,
173 			&childPid,
174 			&stdIn,
175 			&stdOut,
176 			&stdErr,
177 			&error
178 		);
179 
180 		if ( result != 0 )
181 		{
182 			this.externalWatch = externalWatch;
183 			g_child_watch_add(childPid, cast(GChildWatchFunc)(&childWatchCallback), cast(void*)this);
184 			standardInput = fdopen(stdIn, Str.toStringz("w"));
185 			standardOutput = fdopen(stdOut, Str.toStringz("r"));
186 			standardError = fdopen(stdErr, Str.toStringz("r"));
187 
188 			if ( readOutput !is null )
189 			{
190 				(new ReadFile(standardOutput, readOutput)).start();
191 			}
192 			if ( readError !is null )
193 			{
194 				(new ReadFile(standardError, readError)).start();
195 			}
196 		}
197 
198 		return result;
199 	}
200 
201 	class ReadFile : Thread
202 	{
203 		bool delegate(string) read;
204 		FILE* file;
205 
206 		int lineCount;
207 
208 		this(FILE* file, bool delegate (string) read )
209 		{
210 			this.file = file;
211 			this.read = read;
212 
213 			super(&run);
214 		}
215 
216 		public void run()
217 		{
218 			string line = readLine(file);
219 			while( line !is null )
220 			{
221 				++lineCount;
222 				if ( read !is null )
223 				{
224 					read(line);
225 				}
226 				line = readLine(file);
227 			}
228 		}
229 	}
230 
231 	private string readLine(FILE* stream, int max=4096)
232 	{
233 		if ( feof(stream) )
234 		{
235 			if ( externalWatch !is null )
236 			{
237 				externalWatch(this);
238 			}
239 			return null;
240 		}
241 		string line;
242 		line.length = max+1;
243 		char* lineP = fgets(Str.toStringz(line), max, stream);
244 		if ( lineP is null )
245 		{
246 			return "";
247 		}
248 		size_t l = strlen(line.ptr);
249 		if ( l > 0 ) --l;
250 
251 		return line[0..l];
252 	}
253 
254 	extern(C) static void childWatchCallback(int pid, int status, Spawn spawn)
255 	{
256 		//writefln("Spawn.childWatchCallback %s %s", pid, status);
257 		spawn.exitStatus = status;
258 		if ( spawn.externalWatch !is null )
259 		{
260 			spawn.externalWatch(spawn);
261 		}
262 		spawn.close();
263 	}
264 
265 
266 	public bool endOfOutput()
267 	{
268 		if ( standardOutput is null ) return true;
269 		return feof(standardOutput) != 0;
270 	}
271 
272 	public bool endOfError()
273 	{
274 		if ( standardError is null ) return true;
275 		return feof(standardError) != 0;
276 	}
277 
278 	string getOutputString()
279 	{
280 		return Str.toString(strOutput);
281 	}
282 
283 	string getErrorString()
284 	{
285 		return Str.toString(strError);
286 	}
287 
288 	int getExitStatus()
289 	{
290 		return exitStatus;
291 	}
292 
293 	/**
294 	 * Executes a command synchronasly and
295 	 * optionally calls delegates for sysout, syserr and end of job
296 	 *
297 	 */
298 	public int commandLineSync(
299 		ChildWatch externalWatch = null,
300 		bool delegate(string) readOutput = null,
301 	bool delegate(string) readError = null )
302 	{
303 		string commandLine;
304 		foreach ( count, string arg; argv)
305 		{
306 			if ( count > 0 )
307 			{
308 				commandLine ~= ' ';
309 			}
310 			commandLine ~= arg;
311 		}
312 		int status = g_spawn_command_line_sync(
313 			Str.toStringz(commandLine),
314 			&strOutput,
315 			&strError,
316 			&exitStatus,
317 			&error);
318 		if ( readOutput != null )
319 		{
320 			foreach ( string line ; splitLines(Str.toString(strOutput)) )
321 			{
322 				readOutput(line);
323 			}
324 		}
325 		if ( readError != null )
326 		{
327 			foreach ( string line ; splitLines(Str.toString(strError)) )
328 			{
329 				readError(line);
330 			}
331 		}
332 		if ( externalWatch != null )
333 		{
334 			externalWatch(this);
335 		}
336 		return status;
337 	}
338 
339 	/**
340 	 */
341 
342 	/**
343 	 * Executes a child program asynchronously.
344 	 *
345 	 * See g_spawn_async_with_pipes() for a full description; this function
346 	 * simply calls the g_spawn_async_with_pipes() without any pipes.
347 	 *
348 	 * You should call g_spawn_close_pid() on the returned child process
349 	 * reference when you don't need it any more.
350 	 *
351 	 * If you are writing a GTK application, and the program you are spawning is a
352 	 * graphical application too, then to ensure that the spawned program opens its
353 	 * windows on the right screen, you may want to use #GdkAppLaunchContext,
354 	 * #GAppLaunchContext, or set the %DISPLAY environment variable.
355 	 *
356 	 * Note that the returned @child_pid on Windows is a handle to the child
357 	 * process and not its identifier. Process handles and process identifiers
358 	 * are different concepts on Windows.
359 	 *
360 	 * Params:
361 	 *     workingDirectory = child's current working
362 	 *         directory, or %NULL to inherit parent's
363 	 *     argv = child's argument vector
364 	 *     envp = child's environment, or %NULL to inherit parent's
365 	 *     flags = flags from #GSpawnFlags
366 	 *     childSetup = function to run in the child just before exec()
367 	 *     userData = user data for @child_setup
368 	 *     childPid = return location for child process reference, or %NULL
369 	 *
370 	 * Returns: %TRUE on success, %FALSE if error is set
371 	 *
372 	 * Throws: GException on failure.
373 	 */
374 	public static bool async(string workingDirectory, string[] argv, string[] envp, GSpawnFlags flags, GSpawnChildSetupFunc childSetup, void* userData, out GPid childPid)
375 	{
376 		GError* err = null;
377 
378 		auto __p = g_spawn_async(Str.toStringz(workingDirectory), Str.toStringzArray(argv), Str.toStringzArray(envp), flags, childSetup, userData, &childPid, &err) != 0;
379 
380 		if (err !is null)
381 		{
382 			throw new GException( new ErrorG(err) );
383 		}
384 
385 		return __p;
386 	}
387 
388 	/**
389 	 * An old name for g_spawn_check_wait_status(), deprecated because its
390 	 * name is misleading.
391 	 *
392 	 * Despite the name of the function, @wait_status must be the wait status
393 	 * as returned by g_spawn_sync(), g_subprocess_get_status(), `waitpid()`,
394 	 * etc. On Unix platforms, it is incorrect for it to be the exit status
395 	 * as passed to `exit()` or returned by g_subprocess_get_exit_status() or
396 	 * `WEXITSTATUS()`.
397 	 *
398 	 * Deprecated: Use g_spawn_check_wait_status() instead, and check whether your code is conflating wait and exit statuses.
399 	 *
400 	 * Params:
401 	 *     waitStatus = A status as returned from g_spawn_sync()
402 	 *
403 	 * Returns: %TRUE if child exited successfully, %FALSE otherwise (and
404 	 *     @error will be set)
405 	 *
406 	 * Since: 2.34
407 	 *
408 	 * Throws: GException on failure.
409 	 */
410 	public static bool checkExitStatus(int waitStatus)
411 	{
412 		GError* err = null;
413 
414 		auto __p = g_spawn_check_exit_status(waitStatus, &err) != 0;
415 
416 		if (err !is null)
417 		{
418 			throw new GException( new ErrorG(err) );
419 		}
420 
421 		return __p;
422 	}
423 
424 	/**
425 	 * On some platforms, notably Windows, the #GPid type represents a resource
426 	 * which must be closed to prevent resource leaking. g_spawn_close_pid()
427 	 * is provided for this purpose. It should be used on all platforms, even
428 	 * though it doesn't do anything under UNIX.
429 	 *
430 	 * Params:
431 	 *     pid = The process reference to close
432 	 */
433 	public static void closePid(GPid pid)
434 	{
435 		g_spawn_close_pid(pid);
436 	}
437 
438 	/**
439 	 * A simple version of g_spawn_async() that parses a command line with
440 	 * g_shell_parse_argv() and passes it to g_spawn_async().
441 	 *
442 	 * Runs a command line in the background. Unlike g_spawn_async(), the
443 	 * %G_SPAWN_SEARCH_PATH flag is enabled, other flags are not. Note
444 	 * that %G_SPAWN_SEARCH_PATH can have security implications, so
445 	 * consider using g_spawn_async() directly if appropriate. Possible
446 	 * errors are those from g_shell_parse_argv() and g_spawn_async().
447 	 *
448 	 * The same concerns on Windows apply as for g_spawn_command_line_sync().
449 	 *
450 	 * Params:
451 	 *     commandLine = a command line
452 	 *
453 	 * Returns: %TRUE on success, %FALSE if error is set
454 	 *
455 	 * Throws: GException on failure.
456 	 */
457 	public static bool commandLineAsync(string commandLine)
458 	{
459 		GError* err = null;
460 
461 		auto __p = g_spawn_command_line_async(Str.toStringz(commandLine), &err) != 0;
462 
463 		if (err !is null)
464 		{
465 			throw new GException( new ErrorG(err) );
466 		}
467 
468 		return __p;
469 	}
470 
471 	/**
472 	 * A simple version of g_spawn_sync() with little-used parameters
473 	 * removed, taking a command line instead of an argument vector.
474 	 *
475 	 * See g_spawn_sync() for full details.
476 	 *
477 	 * The @command_line argument will be parsed by g_shell_parse_argv().
478 	 *
479 	 * Unlike g_spawn_sync(), the %G_SPAWN_SEARCH_PATH flag is enabled.
480 	 * Note that %G_SPAWN_SEARCH_PATH can have security implications, so
481 	 * consider using g_spawn_sync() directly if appropriate.
482 	 *
483 	 * Possible errors are those from g_spawn_sync() and those
484 	 * from g_shell_parse_argv().
485 	 *
486 	 * If @wait_status is non-%NULL, the platform-specific status of
487 	 * the child is stored there; see the documentation of
488 	 * g_spawn_check_wait_status() for how to use and interpret this.
489 	 * On Unix platforms, note that it is usually not equal
490 	 * to the integer passed to `exit()` or returned from `main()`.
491 	 *
492 	 * On Windows, please note the implications of g_shell_parse_argv()
493 	 * parsing @command_line. Parsing is done according to Unix shell rules, not
494 	 * Windows command interpreter rules.
495 	 * Space is a separator, and backslashes are
496 	 * special. Thus you cannot simply pass a @command_line containing
497 	 * canonical Windows paths, like "c:\\program files\\app\\app.exe", as
498 	 * the backslashes will be eaten, and the space will act as a
499 	 * separator. You need to enclose such paths with single quotes, like
500 	 * "'c:\\program files\\app\\app.exe' 'e:\\folder\\argument.txt'".
501 	 *
502 	 * Params:
503 	 *     commandLine = a command line
504 	 *     standardOutput = return location for child output
505 	 *     standardError = return location for child errors
506 	 *     waitStatus = return location for child wait status, as returned by waitpid()
507 	 *
508 	 * Returns: %TRUE on success, %FALSE if an error was set
509 	 *
510 	 * Throws: GException on failure.
511 	 */
512 	public static bool commandLineSync(string commandLine, out string standardOutput, out string standardError, out int waitStatus)
513 	{
514 		char* outstandardOutput = null;
515 		char* outstandardError = null;
516 		GError* err = null;
517 
518 		auto __p = g_spawn_command_line_sync(Str.toStringz(commandLine), &outstandardOutput, &outstandardError, &waitStatus, &err) != 0;
519 
520 		if (err !is null)
521 		{
522 			throw new GException( new ErrorG(err) );
523 		}
524 
525 		standardOutput = Str.toString(outstandardOutput);
526 		standardError = Str.toString(outstandardError);
527 
528 		return __p;
529 	}
530 
531 	/** */
532 	public static GQuark errorQuark()
533 	{
534 		return g_spawn_error_quark();
535 	}
536 
537 	/** */
538 	public static GQuark exitErrorQuark()
539 	{
540 		return g_spawn_exit_error_quark();
541 	}
542 
543 	/**
544 	 * Executes a child synchronously (waits for the child to exit before returning).
545 	 *
546 	 * All output from the child is stored in @standard_output and @standard_error,
547 	 * if those parameters are non-%NULL. Note that you must set the
548 	 * %G_SPAWN_STDOUT_TO_DEV_NULL and %G_SPAWN_STDERR_TO_DEV_NULL flags when
549 	 * passing %NULL for @standard_output and @standard_error.
550 	 *
551 	 * If @wait_status is non-%NULL, the platform-specific status of
552 	 * the child is stored there; see the documentation of
553 	 * g_spawn_check_wait_status() for how to use and interpret this.
554 	 * On Unix platforms, note that it is usually not equal
555 	 * to the integer passed to `exit()` or returned from `main()`.
556 	 *
557 	 * Note that it is invalid to pass %G_SPAWN_DO_NOT_REAP_CHILD in
558 	 * @flags, and on POSIX platforms, the same restrictions as for
559 	 * g_child_watch_source_new() apply.
560 	 *
561 	 * If an error occurs, no data is returned in @standard_output,
562 	 * @standard_error, or @wait_status.
563 	 *
564 	 * This function calls g_spawn_async_with_pipes() internally; see that
565 	 * function for full details on the other parameters and details on
566 	 * how these functions work on Windows.
567 	 *
568 	 * Params:
569 	 *     workingDirectory = child's current working
570 	 *         directory, or %NULL to inherit parent's
571 	 *     argv = child's argument vector, which must be non-empty and %NULL-terminated
572 	 *     envp = child's environment, or %NULL to inherit parent's
573 	 *     flags = flags from #GSpawnFlags
574 	 *     childSetup = function to run in the child just before exec()
575 	 *     userData = user data for @child_setup
576 	 *     standardOutput = return location for child output, or %NULL
577 	 *     standardError = return location for child error messages, or %NULL
578 	 *     waitStatus = return location for child wait status, as returned by waitpid(), or %NULL
579 	 *
580 	 * Returns: %TRUE on success, %FALSE if an error was set
581 	 *
582 	 * Throws: GException on failure.
583 	 */
584 	public static bool sync(string workingDirectory, string[] argv, string[] envp, GSpawnFlags flags, GSpawnChildSetupFunc childSetup, void* userData, out string standardOutput, out string standardError, out int waitStatus)
585 	{
586 		char* outstandardOutput = null;
587 		char* outstandardError = null;
588 		GError* err = null;
589 
590 		auto __p = g_spawn_sync(Str.toStringz(workingDirectory), Str.toStringzArray(argv), Str.toStringzArray(envp), flags, childSetup, userData, &outstandardOutput, &outstandardError, &waitStatus, &err) != 0;
591 
592 		if (err !is null)
593 		{
594 			throw new GException( new ErrorG(err) );
595 		}
596 
597 		standardOutput = Str.toString(outstandardOutput);
598 		standardError = Str.toString(outstandardError);
599 
600 		return __p;
601 	}
602 
603 	/**
604 	 * Executes a child program asynchronously.
605 	 *
606 	 * Identical to g_spawn_async_with_pipes_and_fds() but with `n_fds` set to zero,
607 	 * so no FD assignments are used.
608 	 *
609 	 * Params:
610 	 *     workingDirectory = child's current working directory, or %NULL to inherit parent's, in the GLib file name encoding
611 	 *     argv = child's argument vector, in the GLib file name encoding;
612 	 *         it must be non-empty and %NULL-terminated
613 	 *     envp = child's environment, or %NULL to inherit parent's, in the GLib file name encoding
614 	 *     flags = flags from #GSpawnFlags
615 	 *     childSetup = function to run in the child just before exec()
616 	 *     userData = user data for @child_setup
617 	 *     childPid = return location for child process ID, or %NULL
618 	 *     stdinFd = file descriptor to use for child's stdin, or `-1`
619 	 *     stdoutFd = file descriptor to use for child's stdout, or `-1`
620 	 *     stderrFd = file descriptor to use for child's stderr, or `-1`
621 	 *
622 	 * Returns: %TRUE on success, %FALSE if an error was set
623 	 *
624 	 * Since: 2.58
625 	 *
626 	 * Throws: GException on failure.
627 	 */
628 	public static bool asyncWithFds(string workingDirectory, string[] argv, string[] envp, GSpawnFlags flags, GSpawnChildSetupFunc childSetup, void* userData, out GPid childPid, int stdinFd, int stdoutFd, int stderrFd)
629 	{
630 		GError* err = null;
631 
632 		auto __p = g_spawn_async_with_fds(Str.toStringz(workingDirectory), Str.toStringzArray(argv), Str.toStringzArray(envp), flags, childSetup, userData, &childPid, stdinFd, stdoutFd, stderrFd, &err) != 0;
633 
634 		if (err !is null)
635 		{
636 			throw new GException( new ErrorG(err) );
637 		}
638 
639 		return __p;
640 	}
641 }